const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
puppeteer.use(StealthPlugin());
const dayjs = require("dayjs");
const axios = require("axios");
const userDataDir = process.env.WEB_CONFIG_USER_DATA_DIR;
const executablePath = process.env.WEB_CONFIG_EXECUTABLE_PATH;
const FACEBOOK_USERNAME = process.env.FACEBOOK_USERNAME;
const FACEBOOK_PASSWORD = process.env.FACEBOOK_PASSWORD;

const logger = require("../../utils/logger");

async function getArticlesInfo(params) {
  let results = [];
  const browser = await puppeteer.launch({
    headless: false,
    userDataDir,
    executablePath,
    defaultViewport: null,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-features=site-per-process",
      "--start-maximized",
      "--disable-notifications",
      //   "--auto-open-devtools-for-tabs",
    ],
    ignoreHTTPSErrors: true,
    // 忽略默认参数 --enable-automation, 防止被检测到是自动化测试
    ignoreDefaultArgs: ["--enable-automation"],
  });
  let page;
  try {
    page = await browser.newPage();
    // 设置 userAgent, 防止被检测到是自动化测试
    await page.setUserAgent(process.env.USER_AGENT);
    const dimensions = await page.evaluate(() => ({
      width: window.innerWidth,
      height: window.innerHeight,
    }));
    logger.info("浏览器窗口实际大小: " + JSON.stringify(dimensions, null, 2));
    await page.setViewport(dimensions);

    await page.goto(
      "https://business.facebook.com/latest/posts/published_posts/?asset_id=442672999178128",
      {
        waitUntil: "networkidle2",
      }
    );
    // 检查是否需要登录
    if (await isLoginPage(page)) {
      logger.info("检测到登录页面，开始登录流程...");
      // 跳转登录页面
      await toLoginPage(page);
      await login(page);
      logger.info("登录成功");
      // 登录后重新导航到目标页面
      await page.goto(
        "https://business.facebook.com/latest/posts/published_posts/?asset_id=442672999178128",
        {
          waitUntil: "networkidle2",
        }
      );
    } else {
      logger.info("已登录");
    }
    // 设置 webdriver 为 false, 防止被检测到是自动化测试
    await page.evaluate(() => {
      Object.defineProperty(navigator, "webdriver", {
        get: () => false,
      });
    });
    // 设置"确定"按钮检查器
    await setupConfirmButtonChecker(page);
    // 选择时间范围
    await selectTimeRange(page, params);
    await new Promise((resolve) => setTimeout(resolve, 3000));
    // 滚动并获取帖子数据
    results = await scrollAndGetPosts(page, params);
    // #TAG: 取消上传图片到cos
    // results = await uploadImagesToCos(results);
    // 格式化results里的publish_time, forEach 遍历  
    results.forEach((item) => {
      if (item.publish_time) {
        item.publish_time = formatDate(item.publish_time);
      }
    });
    return results;
  } catch (error) {
    logger.error(`发生错误: ${error.message}`);
    return [];
  } finally {
    // 确保在关闭浏览器之前停止检查器
    await stopConfirmButtonChecker(page);
    await browser.close();
  }
}
// 滚动并获取帖子数据
async function scrollAndGetPosts(page, params) {
  let previousHeight;
  let scrollAttempts = 0;
  let noNewDataCount = 0;
  const maxNoNewDataAttempts = 3;

  await page.waitForSelector("table");

  while (true) {
    // 滚动表格
    previousHeight = await page.evaluate(() => {
      const table = document.querySelector("table");
      return table.scrollHeight;
    });

    await page.evaluate(() => {
      const table = document.querySelector("table");
      table.scrollTop = table.scrollHeight;
    });

    // 等待新内容加载
    await new Promise((resolve) => setTimeout(resolve, 5000));

    // 检查是否到达表格底部
    const currentHeight = await page.evaluate(() => {
      const tbody = document.querySelector("table tbody");
      return tbody.scrollHeight;
    });
    logger.info(
      `currentHeight: ${currentHeight}, previousHeight: ${previousHeight}`
    );
    if (currentHeight <= previousHeight) {
      noNewDataCount++;
      logger.info(`没有新数据，连续 ${noNewDataCount} 次`);
      if (noNewDataCount >= maxNoNewDataAttempts) {
        logger.info(`连续 ${maxNoNewDataAttempts} 次没有新数据，停止滚动`);
        break;
      }
    } else {
      noNewDataCount = 0;
    }

    scrollAttempts++;
    logger.info(`完成第 ${scrollAttempts} 次滚动`);
  }

  logger.info("滚动结束，开始获取所有帖子数据");

  // 获取所有帖子数据
  const allPosts = await page.evaluate(() => {
    const rows = Array.from(document.querySelectorAll("table tbody tr"));
    return rows.map((row) => {
      const titleElement = row.querySelector(
        'td[aria-colindex="2"]>div>div>div>div:nth-child(2)>div'
      );
      const dateElement = row.querySelector('td[aria-colindex="3"]');
      const title = titleElement ? titleElement.textContent.trim() : "无标题";
      const publish_time = dateElement ? dateElement.textContent.trim() : "";
      const cover = row.querySelector(
        'td[aria-colindex="2"]>div>div>div>div>div img'
      );
      const total_reach = row.querySelector(
        'td[aria-colindex="5"]>div>div>span'
      );
      return {
        title: title,
        publish_time: publish_time,
        cover: JSON.stringify([cover ? cover.src : ""]),
        total_reach: total_reach ? total_reach.textContent.trim() : "",
      };
    });
  });
  logger.info(`共获取到 ${allPosts.length} 条帖子`);
  // 遍历所有帖子并获取详细信息
  for (let i = 0; i < allPosts.length; i++) {
    logger.info(`正在获取第 ${i + 1}/${allPosts.length} 条帖子的详细信息`);
    const details = await getPostDetails(page, i);
    Object.assign(allPosts[i], details);
    logger.info(
      `第 ${i + 1}/${allPosts.length} 条帖子详细信息: ${JSON.stringify(
        details
      )}`
    );
    // 等待一段时间再处理下一个帖子，避免请求过于频繁
    // 防止反爬虫机制，时间随机4-6秒
    await new Promise((resolve) =>
      setTimeout(resolve, Math.random() * 2000 + 4000)
    );
  }

  return allPosts;
}
// 获取帖子详细信息
async function getPostDetails(page, index) {
  return new Promise(async (resolve, reject) => {
    try {
      let graphqlResponses = [];
      const listener = async (response) => {
        if (
          response.url().includes("https://business.facebook.com/api/graphql/")
        ) {
          const request = response.request();
          const postData = request.postData();
          // 解析响应体
          const responseBody = await response.text();
          if (
            postData.includes("useBusinessContentByIDsQuery") ||
            postData.includes(
              "BusinessContentManagerObjectTemplateQueryRootQuery"
            )
          ) {
            graphqlResponses.push({
              requestData: postData ? parseUrlEncodedData(postData) : null,
              responseData: JSON.parse(responseBody),
            });
          }
        }
      };

      page.on("response", listener);

      // 点击帖子行
      await page.evaluate((idx) => {
        const rows = document.querySelectorAll("table tbody tr");
        if (rows[idx]) {
          rows[idx].click();
        }
      }, index);

      // 等待一段时间以确保所有响应都被捕获
      await new Promise((resolve) => setTimeout(resolve, 5000));

      // 停止监听
      page.off("response", listener);

      // 解析所有捕获的响应
      const details = parseGraphQLResponses(graphqlResponses);
      resolve(details);
    } catch (error) {
      reject(error);
    }
  });
}
// 解析URL编码数据
function parseUrlEncodedData(data) {
  const result = {};
  const pairs = data.split("&");
  for (const pair of pairs) {
    const [key, value] = pair.split("=");
    result[decodeURIComponent(key)] = decodeURIComponent(value);
  }
  return result;
}
// 解析GraphQL响应
function parseGraphQLResponses(responses) {
  const details = {};
  for (const { requestData, responseData } of responses) {
    if (
      requestData.fb_api_req_friendly_name === "useBusinessContentByIDsQuery"
    ) {
      const content = responseData.data?.tofu_business_content?.contents?.[0];
      if (!content) {
        logger.warn("无法获取 content，跳过当前数据");
        continue;
      }
      Object.assign(details, {
        id: content.id,
        cover: JSON.stringify([content.media_thumbnail_uri || ""]),
        url: content.permalink_uri,
      });
    }
    if (
      requestData.fb_api_req_friendly_name ===
      "BusinessContentManagerObjectTemplateQueryRootQuery"
    ) {
      logger.info(`获取到响应数据，并解析`);
      const content = responseData.data?.node?.business_content_insights;
      const publish_time = responseData.data?.node?.creation_time;
      if (!content || !publish_time) {
        logger.warn("无法获取 content 或 publish_time，跳过当前数据");
        continue;
      }

      // 其余代码保持不变
      const reach_count = Number(content.total_reach);
      const impression_count = Number(content.total_impression);
      const like_count = Number(content.total_reaction);
      const comment_count = Number(content.total_comments);
      const share_count = Number(content.total_shares);
      const collect_count = Number(content.total_saves);
      const bucket_value = content?.clicks_breakdown?.bucket_values || [];
      const link_click_count = bucket_value?.find((item) =>
        item.bucket_names.includes("LINK_CLICK")
      );
      //字段：标题、图片、id、覆盖人数、展示次数、互动次数、点赞、评论数量、分享次数、收藏次数、链接点击量
      // 标题：title
      // 图片：cover
      // id：id
      // 详情：url
      // 覆盖人数：reach_count
      // 展示次数：impression_count
      // 互动次数：interaction_count
      // 点赞：like_count
      // 评论数量：comment_count
      // 分享次数：share_count
      // 收藏次数：collect_count
      // 链接点击量：link_click_count
      Object.assign(details, {
        reach_count,
        impression_count,
        interaction_count:
          like_count + comment_count + share_count + collect_count,
        like_count,
        comment_count,
        share_count,
        collect_count,
        link_click_count: link_click_count ? link_click_count.bucket_value : 0,
        publish_time: dayjs.unix(publish_time).format("YYYY-MM-DD HH:mm:ss"),
      });
    }
  }
  return details;
}
// 选择时间范围
async function selectTimeRange(page, params) {
  await page.waitForSelector("table");
  //  获取日期选择框的位置
  const elementInfo = await page.evaluate(() => {
    const table = document.querySelector("table");
    const div =
      table.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.firstChild.querySelector(
        "div:nth-child(5)"
      );
    if (div) {
      const rect = div.getBoundingClientRect();
      return {
        x: rect.left + rect.width / 2,
        y: rect.top + rect.height / 2,
        width: rect.width,
        height: rect.height,
      };
    }
    return null;
  });
  if (elementInfo) {
    logger.info("找到日期选择框元素");

    // 移动鼠标到元素中心
    await page.mouse.move(elementInfo.x, elementInfo.y);
    logger.info("鼠标已移动到元素上");

    // 短暂等待
    await new Promise((resolve) => setTimeout(resolve, 1000));

    // 点击元素
    await page.mouse.click(elementInfo.x, elementInfo.y);
    logger.info("已点击日期选择框");

    // 等待弹窗出现
    await page.waitForSelector('div[data-testid="ContextualLayerRoot"]');
    await new Promise((resolve) => setTimeout(resolve, 1000));
    // 选择时间范围
    if (params.update_type === "highFrequency") {
      await page.evaluate(() => {
        const datePicker = document.querySelector(
          'div[data-testid="ContextualLayerRoot"]'
        );
        Array.from(datePicker.querySelectorAll("label")).forEach((label) => {
          if (label.textContent.includes("过去 7 天")) {
            // if (label.textContent.includes("昨天")) {
            label.click();
          }
        });
      });
    } else {
      await page.evaluate(() => {
        const datePicker = document.querySelector(
          'div[data-testid="ContextualLayerRoot"]'
        );
        Array.from(datePicker.querySelectorAll("label")).forEach((label) => {
          if (label.textContent.includes("过去 28 天")) {
            label.click();
          }
        });
      });
    }
  } else {
    logger.error("未找到日期选择框元素");
  }
}

// 检查是否跳转到登录页面
async function isLoginPage(page) {
  const currentUrl = page.url();
  return currentUrl.includes(
    "https://business.facebook.com/business/loginpage/"
  );
}

// 跳转登录页面
async function toLoginPage(page) {
  // 获取登录按钮，点击，登录按钮是第一个 div tabindex=0
  const loginButton = await page.$('div[tabindex="0"]');
  if (loginButton) {
    await loginButton.click();
  } else {
    logger.error("未找到登录按钮");
  }
}
// 登录
async function login(page) {
  // 等待登录表单加载
  await page.waitForSelector("#email");
  await page.waitForSelector("#pass");

  // 输入用户名和密码
  await page.type("#email", FACEBOOK_USERNAME, { delay: 100 });
  await page.type("#pass", FACEBOOK_PASSWORD, { delay: 100 });

  // 点击登录按钮
  await page.click('button[name="login"]');

  // 等待导航完成
  await page.waitForNavigation({ waitUntil: "networkidle0" });
}
//检测弹窗出现就关闭
async function setupConfirmButtonChecker(page) {
  await page.evaluate(() => {
    window.confirmButtonInterval = setInterval(() => {
      const confirmButton = document.querySelector('div[aria-label="确定"]');
      if (confirmButton) {
        confirmButton.click();
        console.log('点击了"确定"按钮');
      }
    }, 500); // 每500毫秒检查一次
  });

  logger.info('已设置"确定"按钮检查器');
}
// 停止定时器的函数
async function stopConfirmButtonChecker(page) {
  await page.evaluate(() => {
    if (window.confirmButtonInterval) {
      clearInterval(window.confirmButtonInterval);
      delete window.confirmButtonInterval;
    }
  });

  logger.info('已停止"确定"按钮检查器');
}
// 上传图片到cos, 一张一张上传，控制时间间隔 1000ms 一次
async function uploadImagesToCos(results) {
  for (const item of results) {
    try {
      const cover = JSON.parse(item.cover);
      if (cover.length > 0 && cover[0]) {
        try {
          logger.info(`上传图片: ${cover[0]}`);
          const response = await axios.post(
            `${process.env.COS_UPLOAD_BASE_URL}/api/v1/uploadCos`,
            {
              url: cover[0],
            }
          );
          if (response.data.success) {
            item.cover = response.data.url;
            logger.info(`上传图片成功: ${response.data.url}`);
          } else {
            logger.warn(`上传图片失败: ${cover[0]}`);
          }
        } catch (error) {
          logger.error(`上传图片时发生错误: ${error.message}`);
        }
      }
    } catch (error) {
      logger.error(`处理图片时发生错误: ${error.message}`);
    }
    await new Promise((resolve) => setTimeout(resolve, 1000));
  }
  return results;
}
// 格式化日期
function formatDate(dateStr) {
  // 检查是否是中文格式 (10月14日 21:00)
  if (dateStr.includes('月') && dateStr.includes('日')) {
    return dayjs(dateStr, 'MM月DD日 HH:mm')
      .year(new Date().getFullYear()) // 使用当前年份
      .format('YYYY-MM-DD HH:mm:ss');
  }
  // 标准格式 (2024-10-14 21:00:00)
  return dayjs(dateStr).format('YYYY-MM-DD HH:mm:ss');
}


exports.handleCommand = async (command, params) => {
  switch (command) {
    case "getArticlesInfo":
      const data = await getArticlesInfo(params);
      return { data };
    default:
      throw new Error("不支持的命令");
  }
};
